package org.farm2.skc.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.farm2.base.db.FarmDbFields;
import org.farm2.base.domain.FarmUserContextLoader;
import org.farm2.base.event.enums.F2EActionT;
import org.farm2.base.event.enums.F2EObjectT;
import org.farm2.base.event.face.Farm2Events;
import org.farm2.base.exception.FarmAppException;
import org.farm2.base.exception.FarmExceptionUtils;
import org.farm2.base.password.FarmPasswordEncoder;
import org.farm2.files.domain.ResourceFile;
import org.farm2.files.domain.ex.FarmFilePath;
import org.farm2.files.service.ResourceFileServiceInter;
import org.farm2.files.utils.Farm2RegisteTypeEnum;
import org.farm2.skc.dao.SkcKnowDao;
import org.farm2.skc.dao.SkcKnowFileDao;
import org.farm2.skc.dao.SkcKnowTagDao;
import org.farm2.skc.dao.SkcKnowVersionDao;
import org.farm2.skc.domain.SkcKnow;
import org.farm2.skc.domain.SkcKnowFile;
import org.farm2.skc.domain.SkcKnowTag;
import org.farm2.skc.domain.SkcKnowVersion;
import org.farm2.skc.dto.web.IndexTagsDto;
import org.farm2.skc.dto.web.WebKnowDto;
import org.farm2.skc.dto.web.WebTagDto;
import org.farm2.skc.enums.FarmKnowFileMarkEnum;
import org.farm2.skc.enums.KnowFileTypeEnum;
import org.farm2.skc.enums.KnowModelEnum;
import org.farm2.skc.enums.KnowStateEnum;
import org.farm2.skc.service.SkcKnowServiceInter;
import org.farm2.skc.utils.SkcFileMarkUtils;
import org.farm2.tools.bean.FarmBeanUtils;
import org.farm2.tools.db.DataQuery;
import org.farm2.tools.db.DataResult;
import org.farm2.tools.db.commons.DBRule;
import org.farm2.tools.db.commons.DBRuleList;
import org.farm2.tools.files.Farm2FileUtils;
import org.farm2.tools.i18n.I18n;
import org.farm2.tools.i18n.string.FarmStringUtils;
import org.farm2.tools.time.FarmTimeTool;
import org.farm2.tools.web.Farm2HtmlUtils;
import org.farm2.tools.web.Farm2HtmlUtilsHandleInter;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**知识 
 * @author cbtg自动生成  2025-2-4 12:13:51 
 */
@Service
@Slf4j
public class SkcKnowServiceImpl implements SkcKnowServiceInter {
    @Autowired
    private SkcKnowVersionDao skcKnowVersionDao;
    @Autowired
    private SkcKnowFileDao skcKnowFileDao;
    @Autowired
    private SkcKnowDao skcKnowDao;
    @Autowired
    private ResourceFileServiceInter resourceFileServiceImpl;
    @Autowired
    private SkcKnowTagDao skcKnowTagDao;
    private static final String KNOW_MAIN_DOC_FILE_HTML_EXNAME = ".html";


    @Transactional
    @Override
    public SkcKnow insertSkcKnowEntity(SkcKnow skcKnow) {
        FarmDbFields.initInsertBean(skcKnow, FarmUserContextLoader.getCurrentUser());
        //FarmBeanUtils.runFunctionByBlank(skcKnow.getType(), "1", skcKnow::setType);
        skcKnowDao.insert(skcKnow);
       //[tree：树形结构使用]
       //initTreeCode(actions.getId());
        return skcKnow;
    }

    @Transactional
    @Override
    public SkcKnow editSkcKnowEntity(SkcKnow skcKnow) {
        SkcKnow saveSkcKnow = getSkcKnowById(skcKnow.getId());
        FarmExceptionUtils.throwNullEx(saveSkcKnow, I18n.msg("知识不存在:?", skcKnow.getId()));
        saveSkcKnow.setId(skcKnow.getId());
        saveSkcKnow.setTitle(skcKnow.getTitle());
        saveSkcKnow.setDocdescribe(skcKnow.getDocdescribe());
        saveSkcKnow.setKnowmodel(skcKnow.getKnowmodel());
        saveSkcKnow.setAuthor(skcKnow.getAuthor());
        saveSkcKnow.setPubtime(skcKnow.getPubtime());
        saveSkcKnow.setSource(skcKnow.getSource());
        saveSkcKnow.setState(skcKnow.getState());
        saveSkcKnow.setCtime(skcKnow.getCtime());
        saveSkcKnow.setEtime(skcKnow.getEtime());
        saveSkcKnow.setCusername(skcKnow.getCusername());
        saveSkcKnow.setCuserkey(skcKnow.getCuserkey());
        saveSkcKnow.setEusername(skcKnow.getEusername());
        saveSkcKnow.setEuserkey(skcKnow.getEuserkey());
        saveSkcKnow.setPcontent(skcKnow.getPcontent());
        saveSkcKnow.setRuninfoid(skcKnow.getRuninfoid());
        saveSkcKnow.setSyncid(skcKnow.getSyncid());
        saveSkcKnow.setVersionid(skcKnow.getVersionid());
        saveSkcKnow.setSno(skcKnow.getSno());
        saveSkcKnow.setValiditys(skcKnow.getValiditys());
        saveSkcKnow.setValiditye(skcKnow.getValiditye());
         
        FarmDbFields.initUpdateBean(saveSkcKnow, FarmUserContextLoader.getCurrentUser());
        skcKnowDao.update(saveSkcKnow);
        return saveSkcKnow;
    }

    @Transactional
    @Override
    public SkcKnow getSkcKnowById(String id) {
        return skcKnowDao.findById(id);
    }

    @Override
    public List<SkcKnow> getSkcKnows(DataQuery query) {
        return skcKnowDao.queryData(query.setCount(false)).getData(SkcKnow.class);
    }



    @Transactional
    @Override
    public DataResult searchSkcKnow(DataQuery query) {
        DataResult result = skcKnowDao.queryData(query);
        return result;
    }

    @Override
    public int getSkcKnowNum(DataQuery query) {
        return skcKnowDao.countData(query);
    }


    @Transactional
    @Override
    public void delSkcKnow(String id) {
        //删除版本
        skcKnowVersionDao.delete(DBRuleList.getInstance().add(new DBRule("KNOWID", id, "=")).toList());
        //删除标签
        skcKnowTagDao.delete(DBRuleList.getInstance().add(new DBRule("KNOWID", id, "=")).toList());
        //删除附件关联信息
        List<SkcKnowFile> kfiles = skcKnowFileDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", id, "=")).toList());
        for (SkcKnowFile kfile : kfiles) {
            resourceFileServiceImpl.cancel(kfile.getFileid(), Farm2RegisteTypeEnum.KNOW, id);
            skcKnowFileDao.deleteById(kfile.getId());
        }
        //注销附件
        skcKnowDao.deleteById(id);
        //注册事件
        Farm2Events.emit(F2EObjectT.KNOW, id, F2EActionT.DELETE);
    }
    
    @Override
    public int getNum(DataQuery query) {
        return  skcKnowDao.countData(query);
    }


    /**
     * 从html中提取知识附件
     *
     * @return
     */
    private List<SkcKnowFile> getFilesByHtml(Document doc) {
        List<SkcKnowFile> sfiles = new ArrayList<>();
        {
            Farm2HtmlUtils.getAttrs(doc, "img", "src", new Farm2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String url) {
                    String id = FarmStringUtils.getFileIdByUrl(url);
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new SkcKnowFile(id, KnowFileTypeEnum.KNOW_IMG));
                        node.attr("src", SkcFileMarkUtils.FARM2_BASEPATH_FLAG + "api/files/download/" + id);
                    }
                }
            });
        }

        {
            Farm2HtmlUtils.getAttrs(doc, "video", "src", new Farm2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String url) {
                    String id = FarmStringUtils.getFileIdByUrl(url);
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new SkcKnowFile(id, KnowFileTypeEnum.KNOW_MEDIA));
                        node.attr("src", SkcFileMarkUtils.FARM2_BASEPATH_FLAG + "api/files/download/" + id);
                    }
                }
            });
        }
        {
            Farm2HtmlUtils.getAttrs(doc, "audio", "src", new Farm2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String url) {
                    String id = FarmStringUtils.getFileIdByUrl(url);
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new SkcKnowFile(id, KnowFileTypeEnum.KNOW_MEDIA));
                        node.attr("src", SkcFileMarkUtils.FARM2_BASEPATH_FLAG + "api/files/download/" + id);
                    }
                }
            });
        }
        {
            Farm2HtmlUtils.getAttrs(doc, "div", "fileid", new Farm2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String id) {
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new SkcKnowFile(id, KnowFileTypeEnum.KNOW_FILE));
                    }
                }
            });
        }
        return sfiles;
    }

    @Override
    public String getKnowText(SkcKnow know) {
        List<SkcKnowFile> files = skcKnowFileDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).add(new DBRule("TYPE", KnowFileTypeEnum.MAIN_DOC.getKey(), "=")).add(new DBRule("VERSIONID", know.getVersionid(), "=")).toList());
        if (files.size() > 0) {
            FarmFilePath filePath = resourceFileServiceImpl.getFilePath(resourceFileServiceImpl.getResourceFileById(files.get(0).getFileid()));
            try {
                String text = Farm2FileUtils.readText(filePath.getFile());
                return text;
            } catch (IOException e) {
                e.printStackTrace();
                return e.getMessage();
            }
        }
        return "";
    }

    @Override
    public String getKnowHtml(SkcKnow know) {
        String text = getKnowText(know);
        Document htmldoc = Jsoup.parse(text);
        Elements videos = htmldoc.getElementsByTag("video");
        for (Element video : videos) {
            video.attr("controls", "true");
        }
        return htmldoc.html();
    }

    /**
     * 创建一个文档附件（保存知识主文档）
     *
     * @param title
     * @param html
     * @return
     */
    private ResourceFile creatKnowFile(String title, String html) {
        ResourceFile rfile = resourceFileServiceImpl.saveFile(title + KNOW_MAIN_DOC_FILE_HTML_EXNAME, html);
        return rfile;
    }

    private SkcKnowVersion creatVersion(String title, String knowid) {
        SkcKnowVersion version = new SkcKnowVersion();
        FarmDbFields.initInsertBean(version, FarmUserContextLoader.getCurrentUser());
        if (StringUtils.isBlank(knowid)) {
            version.setKnowid("NONE");
        } else {
            version.setKnowid(knowid);
        }
        version.setState("2");
        version.setTitle(title);
        skcKnowVersionDao.insert(version);
        return version;
    }

    private void bindTags(SkcKnow know, List<WebTagDto> tags) {
        skcKnowTagDao.delete(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).toList());
        for (WebTagDto wtag : tags) {
            SkcKnowTag tag = new SkcKnowTag();
            FarmDbFields.initInsertBean(tag, FarmUserContextLoader.getCurrentUser());
            tag.setNote(wtag.getName());
            tag.setKnowid(know.getId());
            tag.setTagkey(wtag.getTagkey());
            tag.setType(wtag.getType());
            tag.setTitle(wtag.getName());
            skcKnowTagDao.insert(tag);
        }
    }

    /**
     * 设置附件的应用标记
     *
     * @param kfile
     */
    private void initFileMark(SkcKnowFile kfile) {
        ResourceFile rfile = resourceFileServiceImpl.getResourceFileById(kfile.getFileid());
        if (rfile != null && Farm2FileUtils.isImg(rfile.getExname())) {
            File file = resourceFileServiceImpl.getFile(rfile);
            if (Farm2FileUtils.viewImg(file, rfile.getExname())) {
                String mark = kfile.getMark();
                if (mark == null) {
                    mark = FarmKnowFileMarkEnum.viewImg.getKey();
                } else {
                    mark = mark.replace(FarmKnowFileMarkEnum.viewImg.getKey(), "");
                    mark = mark + FarmKnowFileMarkEnum.viewImg.getKey();
                }
                kfile.setMark(mark);
            }
        }
        //  kfile.setMark();
        kfile.setExname(rfile.getExname());
    }

    @Transactional
    @Override
    public SkcKnow creatKnow(WebKnowDto webKnowDto) {
        List<SkcKnowFile> sfiles = new ArrayList<>();
        String html = webKnowDto.getText();
        Document doc = Jsoup.parse(html);
        sfiles.addAll(getFilesByHtml(doc));
        {//创建附件
            ResourceFile mianFile = creatKnowFile(webKnowDto.getTitle(), doc.html());
            sfiles.add(new SkcKnowFile(mianFile.getId(), KnowFileTypeEnum.MAIN_DOC));
        }
        //创建版本
        SkcKnowVersion version = creatVersion(webKnowDto.getTitle(), null);
        //创建知识
        SkcKnow know = new SkcKnow();
        {
            FarmDbFields.initInsertBean(know, FarmUserContextLoader.getCurrentUser());
            know.setAuthor(FarmUserContextLoader.getCurrentUser().getName());
            know.setDocdescribe(webKnowDto.getDocdescribe());
            know.setKnowmodel(KnowModelEnum.DOC_KNOW.getKey());
            know.setPubtime(FarmTimeTool.getTimeDate14());
            know.setRuninfoid("NONE");
            know.setState(KnowStateEnum.ABLE.getKey());
            know.setTitle(webKnowDto.getTitle());
            know.setSyncid(version.getId());
            know.setVersionid(version.getId());
            skcKnowDao.insert(know);
        }
        for (SkcKnowFile kfile : sfiles) {
            kfile.setVersionid(version.getId());
            kfile.setKnowid(know.getId());
            initFileMark(kfile);
            skcKnowFileDao.insert(kfile);
            resourceFileServiceImpl.submit(kfile.getFileid(), Farm2RegisteTypeEnum.KNOW, know.getId());
        }
        //绑定知识标签
        {
            bindTags(know, webKnowDto.getTags());
        }
        version.setKnowid(know.getId());
        skcKnowVersionDao.update(version);
        //注册事件
        Farm2Events.emit(F2EObjectT.KNOW, know.getId(), F2EActionT.ADD);
        return know;
    }

    @Transactional
    @Override
    public SkcKnow editKnow(WebKnowDto webKnowDto) {
        List<SkcKnowFile> sfiles = new ArrayList<>();
        String html = webKnowDto.getText();
        Document doc = Jsoup.parse(html);
        sfiles.addAll(getFilesByHtml(doc));
        {//创建附件
            ResourceFile mianFile = creatKnowFile(webKnowDto.getTitle(), doc.html());
            sfiles.add(new SkcKnowFile(mianFile.getId(), KnowFileTypeEnum.MAIN_DOC));
        }
        //创建版本
        SkcKnowVersion version = creatVersion(webKnowDto.getTitle(), webKnowDto.getId());
        //更新知识
        SkcKnow know = skcKnowDao.findById(webKnowDto.getId());
        {
            FarmDbFields.initUpdateBean(know, FarmUserContextLoader.getCurrentUser());
            //know.setAuthor(FarmUserContextLoader.getCurrentUser().getName());
            know.setDocdescribe(webKnowDto.getDocdescribe());
            //know.setKnowmodel(KnowModelEnum.DOC_KNOW.getKey());
            // know.setPubtime(FarmTimeTool.getTimeDate14());
            // know.setRuninfoid("NONE");
            //know.setState(KnowStateEnum.ABLE.getKey());
            know.setTitle(webKnowDto.getTitle());
            // know.setSyncid(version.getId());
            know.setVersionid(version.getId());
            skcKnowDao.update(know);
        }
        for (SkcKnowFile kfile : sfiles) {
            kfile.setVersionid(version.getId());
            kfile.setKnowid(know.getId());
            initFileMark(kfile);
            skcKnowFileDao.insert(kfile);
            resourceFileServiceImpl.submit(kfile.getFileid(), Farm2RegisteTypeEnum.KNOW, know.getId());
        }
        //绑定知识标签
        {
            bindTags(know, webKnowDto.getTags());
        }
        //注册事件
        Farm2Events.emit(F2EObjectT.KNOW, know.getId(), F2EActionT.UPDATE);
        return know;
    }

    @Override
    public List<String> getInvalidVersionFileIds(SkcKnow know) {
        //找到知识所有附件
        List<SkcKnowFile> skfiles = skcKnowFileDao.
                find(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).toList());
        Set<String> all = new HashSet<>();
        all.addAll(skfiles.stream().map(b -> b.getFileid()).toList());
        //找到当前附件
        Set<String> version = new HashSet<>();
        version.addAll(skfiles.stream().filter(b -> (b.getVersionid().equals(know.getVersionid()))).map(b -> b.getFileid()).toList());
        //所有的去掉当前的
        all.removeAll(version);
        return all.stream().toList();
    }

    @Override
    public List<WebTagDto> getKnowTagDtos(SkcKnow know) {
        List<WebTagDto> dTos = new ArrayList<>();
        List<SkcKnowTag> tags = skcKnowTagDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).toList());
        for (SkcKnowTag wTag : tags) {
            WebTagDto dTo = new WebTagDto();
            dTo.setName(wTag.getTitle());
            dTo.setType(wTag.getType());
            dTo.setTagkey(wTag.getTagkey());
            dTos.add(dTo);
        }
        return dTos;
    }

    @Override
    public IndexTagsDto getKnowIndexTags(SkcKnow know) {
        List<WebTagDto> tags = getKnowTagDtos(know);
        //1系统绑定，2系统可选，3自定义,0特殊标签
        StringBuffer keys = new StringBuffer();
        StringBuffer titles = new StringBuffer();
        for (WebTagDto tag : tags) {
            if (tag.getType().equals("1") || tag.getType().equals("2")) {
                keys.append("," + tag.getTagkey());
                titles.append("," + tag.getName());
            }
            if (tag.getType().equals("3")) {
                titles.append("," + tag.getName());
            }
        }
        IndexTagsDto bt = new IndexTagsDto();
        bt.setKeys(keys.toString());
        bt.setTitles(titles.toString());
        return bt;
    }

    @Override
    public List<String> getImgView(String knowid) {
        List<SkcKnowFile> ksfile = skcKnowFileDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", knowid, "=")).add(new DBRule("MARK", FarmKnowFileMarkEnum.viewImg.getKey(), "like")).toList());
        return ksfile.stream().map(node -> node.getFileid()).distinct().toList();
    }

    @Override
    public int getKnowNumByUser(String userKey) {
        return skcKnowDao.countData(DBRuleList.getInstance()//
                .add(new DBRule("CUSERKEY", userKey, "="))//
                .toList());
    }

    @Override
    public int getNewKnowsNum(String userKey) {
        String time14 = FarmTimeTool.getTimeDate14ForDay(-2, new Date());
        return skcKnowDao.countData(DBRuleList.getInstance()//
                .add(new DBRule("ETIME", time14, ">"))//
                .toList());
    }

    @Override
    public List<String> getKnowFiles(String knowid, String typekey) {
        SkcKnow know = getSkcKnowById(knowid);
        DBRuleList list = DBRuleList.getInstance().add(new DBRule("KNOWID", knowid, "="))
                .add(new DBRule("VERSIONID", know.getVersionid(), "="));
        if (typekey != null) {
            list.add(new DBRule("TYPE", typekey, "="));
        }
        List<SkcKnowFile> kfiles = skcKnowFileDao.find(list.toList());
        List<String> ids = new ArrayList<>();
        for (SkcKnowFile kfile : kfiles) {
            ids.add(kfile.getFileid());
        }
        return ids;
    }
}
